﻿#region Copyright(c) 2006 ZO, All right reserved.
// -----------------------------------------------------------------------------
// Copyright(c) 2006 ZO, All right reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//   1.  Redistribution of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//   2.  Redistribution in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//   3.  The name of the author may not be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// -----------------------------------------------------------------------------
#endregion


#region Using directives

using System;
using System.Drawing;
using System.Globalization;
using System.Web;
using ZO.SmartCore.Helpers;
using ArgumentNullException= ZO.SmartCore.Core.ArgumentNullException;

#endregion

namespace ZO.SmartCore.Configuration
{
    /// <summary>
    /// Represents a section within a configuration file.
    /// </summary>
    public sealed class Section : IConfiguration
    {

        #region Constructors
        /// <summary>
        /// Initializes a new instance of the <see cref="Section"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        public Section(string name)
        {
            if (String.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name");
            }
            this._Name = name;
        } // Section


        /// <summary>
        /// Initializes a new instance of the <see cref="Section"/> class.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="comment">The comment.</param>
        public Section(string name, string comment)
            : this(name)
        {
            this._Comment = comment;

        } // Section
        #endregion

        #region Destructor

        #endregion

        #region Fields
        private SectionKeyCollection _Keys = new SectionKeyCollection();

        private SectionCollection _Sections = new SectionCollection();
        private string _Name;
        private string _Comment;

        #endregion

        #region Events

        #endregion

        #region Operators

        #endregion

        #region Properties
        /// <summary>
        /// Gets the Section name.
        /// </summary>
        /// <value>The name.</value>
        public string Name
        {
            get { return _Name; }
        }

        /// <summary>
        /// Gets or sets the section comment.
        /// </summary>
        /// <value>The comment.</value>
        public string Comment
        {
            get
            {
                return _Comment;
            }
            set
            {
                _Comment = value;
            }
        }

        /// <summary>
        /// Gets the keys.
        /// </summary>
        /// <value>The keys.</value>
        public SectionKeyCollection Keys
        {
            get
            {
                return _Keys;
            }
        }

        /// <summary>
        /// Gets or sets the sections.
        /// </summary>
        /// <value>The sections.</value>
        public SectionCollection Sections
        {
            get { return _Sections; }
        }
        #endregion

        #region Methods

        #endregion

      

        #region IConfiguration Members


        /// <summary>
        /// Reads a string value from the Configuration. If the section or key was not found,
        /// this method returns an empty string value.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <returns>
        /// The requested string value or an empty string if not found.
        /// </returns>
        public string Read(string key)
        {
            return this.Keys[key].Value;
        }


        /// <summary>
        /// Reads a string value from the Configuration. If the section or key was not found,
        /// this method returns the value passed in defaultValue.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <param name="defaultValue">The string value to return if the section or key is not found.</param>
        /// <returns>
        /// The requested string value or defaultValue if not found.
        /// </returns>
        public string Read(string key, string defaultValue)
        {
            SectionKey temp;

            string value;

            temp = this.Keys[key];

            if (temp == null | String.IsNullOrEmpty(temp.Value))
            {
                value = defaultValue;
            }
            else
            {
                value = temp.Value;
            }

            return value;
        }

        /// <summary>
        /// Writes a string value to the Configuration.
        /// </summary>
        /// <param name="key">The key to write to.</param>
        /// <param name="value">The string value to write.</param>
        public void Write(string key, string value)
        {
            this.Keys.Add(key, value);
        }

  

        /// <summary>
        /// Reads a Boolean value from the Configuration. If the section or key was not found,
        /// this method returns a Boolean value of false.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <returns>
        /// The requested Boolean value or false if not found.
        /// </returns>
        public bool ReadBoolean(string key)
        {
            return this.ReadBoolean(key, false);

        }

        /// <summary>
        /// Reads a Boolean value from the Configuration. If the section or key was not found,
        /// this method returns the value passed in defaultValue.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <param name="defaultValue">The Boolean value to return if the section or key is not found.</param>
        /// <returns>
        /// The requested Boolean value or or defaultValue if not found.
        /// </returns>
        public bool ReadBoolean(string key, bool defaultValue)
        {
            SectionKey temp;

            bool value;

            temp = this.Keys[key];

            if (temp == null | String.IsNullOrEmpty(temp.Value))
            {
                value = defaultValue;
            }
            else
            {
                Boolean.TryParse(key, out value);
            }

            return value;
        }

        /// <summary>
        /// Reads a char value from the Configuration. If the section or key was not found,
        /// this method returns an null char value.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <returns>
        /// The requested char value or an empty string if not found.
        /// </returns>
        public char ReadChar(string key)
        {
            return this.ReadChar(key, '\0');
        }

        /// <summary>
        /// Reads a char value from the Configuration. If the section or key was not found,
        /// this method returns the value passed in defaultValue.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <param name="defaultValue">The char value to return if the section or key is not found.</param>
        /// <returns>
        /// The requested char value or defaultValue if not found.
        /// </returns>
        public char ReadChar(string key, char defaultValue)
        {
            SectionKey temp;

            char value;

            temp = this.Keys[key];

            if (temp == null | String.IsNullOrEmpty(temp.Value))
            {
                value = defaultValue;
            }
            else
            {
                Char.TryParse(key, out value);
            }

            return value;
        }

        /// <summary>
        /// Reads a Color value from the Configuration. If the section or key was not found,
        /// this method returns a value of zero.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <returns>
        /// The requested Color value or Color.Empty if not found.
        /// </returns>
        public Color ReadColor(string key)
        {
            return this.ReadColor(key, Color.Empty);
        }

        /// <summary>
        /// Reads a Color value from the Configuration. If the section or key was not found,
        /// this method returns the value passed in defaultValue.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <param name="defaultValue">The Color value to return if the section or key is not found.</param>
        /// <returns>
        /// The requested Color value or aDefault if not found.
        /// </returns>
        public Color ReadColor(string key, Color defaultValue)
        {
            SectionKey temp;

            Color value;

            temp = this.Keys[key];

            if (temp == null | String.IsNullOrEmpty(temp.Value))
            {
                value = defaultValue;
            }
            else
            {
                value = ColorHelper.StringToColor(temp.Value);
            }

            return value;
        }

        /// <summary>
        /// Reads a DateTime value from the Configuration. If the section or key was not found,
        /// this method returns a the current date and time.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <returns>
        /// The requested DateTime value or the current date and time if not found.
        /// </returns>
        public DateTime ReadDateTime(string key)
        {
            return this.ReadDateTime(key, DateTime.MinValue);

        }

        /// <summary>
        /// Reads a DateTime value from the Configuration. If the section or key was not found,
        /// this method returns the value passed in defaultValue.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <param name="defaultValue">The DateTime value to return if the section or key is not found.</param>
        /// <returns>
        /// The requested DateTime value or or aDefault if not found.
        /// </returns>
        public DateTime ReadDateTime(string key, DateTime defaultValue)
        {
            SectionKey temp;

            DateTime value;

            temp = this.Keys[key];

            if (temp == null | String.IsNullOrEmpty(temp.Value))
            {
                value = defaultValue;
            }
            else
            {
                DateTime.TryParse(temp.Value, out value);
            }

            return value;
        }

        /// <summary>
        /// Reads a Double value from the Configuration. If the section or key was not found,
        /// this method returns a value of zero.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <returns>
        /// The requested Double value or zero if not found.
        /// </returns>
        public double ReadDouble(string key)
        {
           return this.ReadDouble(key, 0);
        }

        /// <summary>
        /// Reads a Double value from the Configuration. If the section or key was not found,
        /// this method returns the value passed in defaultValue.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <param name="defaultValue">The Double value to return if the section or key is not found.</param>
        /// <returns>
        /// The requested Double value or or defaultValue if not found.
        /// </returns>
        public double ReadDouble(string key, double defaultValue)
        {
            SectionKey temp;

            double value;

            temp = this.Keys[key];

            if (temp == null | String.IsNullOrEmpty(temp.Value))
            {
                value = defaultValue;
            }
            else
            {
                Double.TryParse(key, out value);
            }

            return value;
        }

        /// <summary>
        /// Reads a enumeration element value from the Configuration. If the section or key was not found,
        /// this method returns the value passed in defaultValue.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <param name="enumType">The Type of the enumeration to read.</param>
        /// <param name="defaultValue">The default value to return if the section or key is not found.</param>
        /// <returns>
        /// The requested value or defaultValue if not found.
        /// </returns>
        public object ReadEnum(string key, Type enumType, object defaultValue)
        {
            SectionKey temp;

            object value;

            temp = this.Keys[key];

            if (temp == null | String.IsNullOrEmpty(temp.Value))
            {
                value = defaultValue;
            }
            else
            {
                value = ReflectionHelper.StringToEnum(enumType, temp.Value);
            }

            return value;
        }

        /// <summary>
        /// Reads a Int32 value from the Configuration. If the section or key was not found,
        /// this method returns zero.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <returns>
        /// The requested Int32 value or zero if not found.
        /// </returns>
        public int ReadInt32(string key)
        {
            return this.ReadInt32(key, 0);
        }

        /// <summary>
        /// Reads a System.Int32 value from the Configuration. If the section or key was not found,
        /// this method returns the value passed in defaultValue.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <param name="defaultValue">The Int32 value to return if the section or key is not found.</param>
        /// <returns>
        /// The requested Int32 value or defaultValue if not found.
        /// </returns>
        public int ReadInt32(string key, int defaultValue)
        {
            SectionKey temp;

            int value;

            temp = this.Keys[key];

            if (temp == null | String.IsNullOrEmpty(temp.Value))
            {
                value = defaultValue;
            }
            else
            {
                Int32.TryParse(key, out value);
            }

            return value;
        }

        /// <summary>
        /// Reads a Single value from the Configuration. If the section or key was not found,
        /// this method returns a value of zero.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <returns>
        /// The requested Single value or zero if not found.
        /// </returns>
        public float ReadSingle(string key)
        {
            return this.ReadSingle(key, 0f);
        }

        /// <summary>
        /// Reads a Single value from the Configuration. If the section or key was not found,
        /// this method returns the value passed in defaultValue.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <param name="defaultValue">The Single value to return if the section or key is not found.</param>
        /// <returns>
        /// The requested Single value or or defaultValue if not found.
        /// </returns>
        public float ReadSingle(string key, float defaultValue)
        {

            SectionKey temp;

            float value;

            temp = this.Keys[key];

            if (temp == null | String.IsNullOrEmpty(temp.Value))
            {
                value = defaultValue;
            }
            else
            {
                Single.TryParse(key, out value);
            }

            return value;
        }

        /// <summary>
        /// Reads a string value from the Configuration. If the section or key was not found,
        /// this method returns an empty string value.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <returns>
        /// The requested string value or an empty string if not found.
        /// </returns>
        public string ReadString(string key)
        {
            return this.ReadString(key, String.Empty);
        }

        /// <summary>
        /// Reads a string value from the Configuration. If the section or key was not found,
        /// this method returns an empty string value.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <param name="encoded">If true, the string value is assumed to be in HTTP encoding and will be decoded.</param>
        /// <returns>
        /// The requested string value or an empty string if not found.
        /// </returns>
        public string ReadString(string key, bool encoded)
        {
            return this.ReadString(key, String.Empty, encoded);
        }

        /// <summary>
        /// Reads a string value from the Configuration. If the section or key was not found,
        /// this method returns the value passed in defaultValue.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <param name="defaultValue">The string value to return if the section or key is not found.</param>
        /// <returns>
        /// The requested string value or defaultValue if not found.
        /// </returns>
        public string ReadString(string key, string defaultValue)
        {
            SectionKey temp;

            string value;

            temp = this.Keys[key];

            if (temp == null | String.IsNullOrEmpty(temp.Value))
            {
                value = defaultValue;
            }
            else
            {
                value = temp.Value;
            }

            return value;
        }

        /// <summary>
        /// Reads a string value from the Configuration. If the section or key was not found,
        /// this method returns the value passed in defaultValue.
        /// </summary>
        /// <param name="key">The key to read from.</param>
        /// <param name="defaultValue">The string value to return if the section or key is not found.</param>
        /// <param name="encoded">If true, the string value is assumed to be in HTTP encoding and will be decoded.</param>
        /// <returns>
        /// The requested string value or defaultValue if not found.
        /// </returns>
        public string ReadString(string key, string defaultValue, bool encoded)
        {
            SectionKey temp;

            string value;

            temp = this.Keys[key];

            if (temp == null | String.IsNullOrEmpty(temp.Value))
            {
                value = defaultValue;
            }
            else
            {
                value = HttpUtility.UrlDecode(temp.Value);
            }
            value = HttpUtility.UrlDecode(value);

            return value;
        }
   

        /// <summary>
        /// Writes a Boolean value to the Configuration.
        /// </summary>
        /// <param name="key">The key to write to.</param>
        /// <param name="value">The bool value to write.</param>
        public void WriteBoolean(string key, bool value)
        {
            this.Keys.Add(key, Convert.ToString(value, CultureInfo.CurrentCulture));
        }

        /// <summary>
        /// Writes a char value to the Configuration.
        /// </summary>
        /// <param name="key">The key to write to.</param>
        /// <param name="value">The char value to write.</param>
        public void WriteChar(string key, char value)
        {
            this.Keys.Add(key, Convert.ToString(value, CultureInfo.CurrentCulture));
        }

        /// <summary>
        /// Writes a Color value to the Configuration.
        /// </summary>
        /// <param name="key">The key to write to.</param>
        /// <param name="value">The Color value to write.</param>
        public void WriteColor(string key, Color value)
        {
            this.Keys.Add(key, ColorHelper.ColorToString(value));
        }

        /// <summary>
        /// Writes a DateTime value to the Configuration.
        /// </summary>
        /// <param name="key">The key to write to.</param>
        /// <param name="value">The DateTime value to write.</param>
        public void WriteDateTime(string key, DateTime value)
        {
            this.Keys.Add(key, Convert.ToString(value, CultureInfo.CurrentCulture));
        }

        /// <summary>
        /// Writes a Double value to the Configuration.
        /// </summary>
        /// <param name="key">The key to write to.</param>
        /// <param name="value">The Double value to write.</param>
        public void WriteDouble(string key, double value)
        {
            this.Keys.Add(key, Convert.ToString(value, CultureInfo.CurrentCulture));
        }

        /// <summary>
        /// Writes a enumeration value to the Configuration.
        /// </summary>
        /// <param name="key">The key to write to.</param>
        /// <param name="value">The value to write.</param>
        public void WriteEnum(string key, object value)
        {
            if (value == null)
            {
                return;
            }
            this.Keys.Add(key, value.ToString());
        }

        /// <summary>
        /// Writes a Int32 value to the Configuration.
        /// </summary>
        /// <param name="key">The key to write to.</param>
        /// <param name="value">The Int32 value to write.</param>
        public void WriteInt32(string key, int value)
        {
            this.Keys.Add(key, Convert.ToString(value, CultureInfo.CurrentCulture));
        }

        /// <summary>
        /// Writes a Single value to the Configuration.
        /// </summary>
        /// <param name="key">The key to write to.</param>
        /// <param name="value">The Single value to write.</param>
        public void WriteSingle(string key, float value)
        {
            this.Keys.Add(key, Convert.ToString(value, CultureInfo.CurrentCulture));
        }

        /// <summary>
        /// Writes a string value to the Configuration.
        /// </summary>
        /// <param name="key">The key to write to.</param>
        /// <param name="value">The string value to write.</param>
        public void WriteString(string key, string value)
        {
            this.WriteString(key, value, false);
        }

        /// <summary>
        /// Writes a string value to the Configuration.
        /// </summary>
        /// <param name="key">The key to write to.</param>
        /// <param name="value">The string value to write.</param>
        /// <param name="encoded">If true, the string value will be encoded in HTTP encoding.</param>
        public void WriteString(string key, string value, bool encoded)
        {
            if (encoded)
            {
                this.Keys.Add(key, HttpUtility.UrlEncode(value));
            }
            else
            {

                this.Keys.Add(key, value);
            }
        }

 

        #endregion
    }
}
